package com.fjwt.gz.mgr.web;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import com.alibaba.fastjson2.JSONObject;
import com.fjwt.gz.core.cache.RedisUtil;
import com.fjwt.gz.core.constants.ApiCodeEnum;
import com.fjwt.gz.core.constants.CS;
import com.fjwt.gz.core.jwt.JWTPayload;
import com.fjwt.gz.core.jwt.JWTUtils;
import com.fjwt.gz.core.model.ApiRes;
import com.fjwt.gz.core.model.security.GzUserDetails;
import com.fjwt.gz.core.utils.ApiResBodyAdviceKit;
import com.fjwt.gz.core.utils.JsonKit;
import com.fjwt.gz.core.utils.SpringBeansUtil;
import com.fjwt.gz.mgr.config.SystemYmlConfig;
import com.fjwt.gz.service.impl.SysConfigService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

import static com.fjwt.gz.core.constants.CS.getVersionKeyToken;

/*
* 功能： 自定义springMVC返回数据格式
*
* @author wg
* @site https://pt.jdyd.xyz/
* @date 2021/6/8 17:12
*/
@ControllerAdvice
public class ApiResBodyAdvice implements ResponseBodyAdvice {

    /** 判断哪些需要拦截 **/
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    /**
     * 拦截返回数据处理
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        List<String> list = request.getHeaders().get("iToken");
        if (list != null && list.size() > 0) {
            if (list.size() == 1 && Objects.equals(list.get(0), "undefined")) {
                //处理扩展字段
                return ApiResBodyAdviceKit.beforeBodyWrite(body);
            }
            JWTPayload jwtPayload = JWTUtils.parseToken(list.get(0), SpringBeansUtil.getBean(SystemYmlConfig.class).getJwtSecret());//反解析token信息
            //token字符串解析失败
            if (jwtPayload == null || StringUtils.isEmpty(jwtPayload.getCacheKey())) {
                throw new RuntimeException("token解析失败");
            }
            GzUserDetails jwtBaseUser = RedisUtil.getObject(jwtPayload.getCacheKey(), GzUserDetails.class);
            if (jwtBaseUser == null || jwtBaseUser.getSysUserId() == null) {
                //处理扩展字段
                return ApiResBodyAdviceKit.beforeBodyWrite(body);
            }
            Long userId = jwtBaseUser.getSysUserId();

            // 如果为 ApiRes && code为成功态 根据设置做数据传输的加密项  && 系统配置的为传输加密
            if (body instanceof ApiRes && ((ApiRes) body).getCode() != null && ((ApiRes) body).getCode().equals(ApiCodeEnum.SUCCESS.getCode())
                    && SysConfigService.HTTP_MSG_IS_ENCRYPT && encryptMatchers(request.getURI().getPath())
            ) {

                // 获取到转换后的格式，并且转回ApiRes
                ApiRes result = ((JSONObject) ApiResBodyAdviceKit.beforeBodyWrite(body)).toJavaObject(ApiRes.class);

                if (ObjectUtils.isNotEmpty(result.getData())) { //若原始数据不为空

                    // 从 Redis 中读取 version
                    String versions = getVersionKeyToken(CS.SYS_ROLE_TYPE.MANAGER, userId, "version");
                    final String versionStr = RedisUtil.getString(versions);
                    String dataKeys = getVersionKeyToken(CS.SYS_ROLE_TYPE.MANAGER, userId, "dataKey");
                    final String dataKeyss = RedisUtil.getString(dataKeys);
                    int version = versionStr != null ? Integer.parseInt(versionStr) : 0;

                    // 获取到转换后的格式，并且转回ApiRes
                    String dataKey = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
                    version += 1;

                    RedisUtil.setString(getVersionKeyToken(CS.SYS_ROLE_TYPE.MANAGER, userId, "dataKey"), dataKey, CS.TOKEN_TIME);
                    RedisUtil.setString(getVersionKeyToken(CS.SYS_ROLE_TYPE.MANAGER, userId, "version"), String.valueOf(version), CS.TOKEN_TIME);


                    JSONObject dynamicKey = new JSONObject();
                    dynamicKey.put("dataKey", dataKey);
                    dynamicKey.put("version", version);

                    JSONObject jsonObject = new JSONObject();

                    jsonObject.put("dynamicKey", dynamicKey);
                    jsonObject.put("data", result.getData());
                    result.setData(jsonObject);
                    SM4 sm4 = SmUtil.sm4(dataKeyss.getBytes());
                    result.setEncryptData(sm4.encryptBase64(JsonKit.newJson("originData", result.getData()).toJSONString()));
                    result.setData(null);
                }
                return result;
            }
        }

        //处理扩展字段
        return ApiResBodyAdviceKit.beforeBodyWrite(body);
    }

    /**
     * 过滤不需要加密的接口
     *
     * @param path
     * @return
     */
    private boolean encryptMatchers(String path) {
        String[] list = new String[]{"/api/anon/siteInfos", "/api/anon/auth/login", "/api/fans/getWxchatPayOpenid", "/api/fans/getPlaceWxchatOpenid", "/api/anon/auth/updatePwd","/api/officialMedia/uploadMedia"};
        String result = Arrays.stream(list).filter(item ->
                item.equals(path)
        ).findFirst().orElse(null);
        return result == null ? true : false;
    }

}
